//
// Created by 成飞 on 2024/3/5.
//
#include "orderkv_w_buffer.h"
#include "config/config_data.h"
#include <iomanip>
#include <filesystem>
#include <sstream>
#include <iostream>

namespace vstore{
    OrderkvWBuffer::OrderkvWBuffer(){
        status = 0;
        init();
    }

    bool OrderkvWBuffer::put(std::string& key, std::string& val) {
//        logger << key << std::endl << val << std::endl;
//        logger.flush();
        fwrite(key.data(), sizeof(char), key.size(), logger);
        fwrite("\n", sizeof(char), 1, logger); // 写入换行符
        fwrite(val.data(), sizeof(char), val.size(), logger);
        fwrite("\n", sizeof(char), 1, logger); // 写入换行符
        return put_without_log(key, val);
    }

    inline bool OrderkvWBuffer::put_without_log(std::string& key, std::string& val){
        auto iter = buffer.find(key);
        if (iter != buffer.end()) {
            iter->second.first = val;
            auto& recordVal = iter->second.second;
            size -= recordVal.recordLen;
            meta::f_off recordLen = 2 * sizeof(meta::f_off) + key.size() + val.size();
            size += recordLen;
            recordVal.recordLen = recordLen;
            return false;
        } else{
            meta::f_off recordLen = 2*sizeof(meta::f_off) + key.size() + val.size() ;
            size += recordLen;
            buffer.insert({key, std::pair{val, lsm::LsmRecordVal{fileNo, 0, recordLen} }});
            return true; //true
        }
    }

    void OrderkvWBuffer::query(const std::string& key, std::string& ret) {
        auto it = buffer.find(key);
        if (it == buffer.end())
            ret = "";
        else
            ret = it->second.first;
    }

    void OrderkvWBuffer::range_query(const string& startKey, const string& endKey, int len, vector<pair<string_view, string_view>>& ret) {
        ret.reserve(len);
        auto startIter = buffer.lower_bound(startKey);
        auto endIter = buffer.upper_bound(endKey);
        int resultNum = 0;
        for (auto iter = startIter; iter != endIter && resultNum < len; ++iter, ++resultNum) {
            ret.emplace_back(iter->first, iter->second.first);
        }
    }

    //sync?
    void OrderkvWBuffer::dump() {
        // 文件路径
        auto filePathStr = conf::data.db.vstore_path + "/vFile" + fileNo8Digits + ".data";
        std::filesystem::path filePath = filePathStr;
        //创建文件夹
        std::filesystem::create_directories(filePath.parent_path());
        // 打开文件流
        std::ofstream outputFile(filePath);
        // 检查文件是否成功打开
        if (!outputFile.is_open()) {
            std::cerr << "Unable to open file: " << filePath << std::endl;
        }

        // 将 std::map 的内容写入文件
        FILE *outputF = fopen(filePath.c_str(), "w+");
        meta::fileControlInfo[fileNo].fd = outputF;
        for (const auto &kvInfoPair: buffer) {
            auto recordLen = kvInfoPair.second.second.recordLen;
            meta::f_off keyLen = kvInfoPair.first.size();
            fwrite(reinterpret_cast<const char *>(&recordLen), sizeof(recordLen), 1, outputF);
            fwrite(reinterpret_cast<const char *>(&keyLen), sizeof(keyLen), 1, outputF);
            fwrite(kvInfoPair.first.data(), sizeof(char), kvInfoPair.first.size(), outputF);
            fwrite(kvInfoPair.second.first.data(), sizeof(char), kvInfoPair.second.first.size(), outputF);
        }
        fflush(outputF);
//        fclose(outputF); //常驻内存就不关了


        //#ifdef WAL
//        meta::fidAddrLogger << fileNo << " " << filePathStr << std::endl;
        meta::fileControlInfo[fileNo].addr = std::move(filePathStr);
//        meta::fidAddrLogger << "ok" << std::endl;

//        meta::storeInfo();
    }

    void OrderkvWBuffer::ready()  {
        init();
        this->fileNo = ++meta::readyFileNo;

        std::ostringstream ss;
        ss << std::setw(8) << std::setfill('0') << fileNo;
        fileNo8Digits = ss.str();
        // 文件路径
        loggerFilePathStr = conf::data.db.vstore_path + "/log" + fileNo8Digits + ".txt";
        std::filesystem::path filePath = loggerFilePathStr;

        logger = fopen(filePath.c_str(), "a");
        fwrite(std::to_string(fileNo).c_str(), sizeof(char), std::to_string(fileNo).size(), logger);
        fwrite("\n", sizeof(char), 1, logger); // 写入换行符

    }

    void OrderkvWBuffer::init() {
        size = 0;
        buffer.clear();
    }
}